package cn.nexd.map.location.collector.util;

import android.hardware.Sensor;

import org.json.JSONException;
import org.json.JSONStringer;

import java.util.ArrayList;
import java.util.List;

import cn.nexd.map.location.collector.bean.BluetoothDataResult;
import cn.nexd.map.location.collector.bean.SensorDataResult;
import cn.nexd.map.location.collector.bean.WifiDataResult;
import cn.nexd.map.location.task.core.SimpleSafeTask;


/**
 * ActiveModeDataUtil create by codingfish at 15/4/27
 * TODO:
 *
 * @Version V1.0
 */
class ActiveModeDataUtil {

    private String scanId;
    private String userId;
    private List<WifiDataResult> wifiDatas;
    private BluetoothDataResult bluetoothData;
    private SensorDataResult sensorData;

    private List<JSONStringer> bluetoothJsonDatas;
    private List<JSONStringer> wifiJsonDatas;
    private List<JSONStringer> sensorJsonDatas;

    private JSONStringer accelerometerJsonStringer;

    private ActiveModeDataUtil() {

        bluetoothJsonDatas = new ArrayList<JSONStringer>();
        wifiJsonDatas = new ArrayList<JSONStringer>();
        sensorJsonDatas = new ArrayList<JSONStringer>();
        accelerometerJsonStringer = new JSONStringer();

    }


    public static ActiveModeDataUtil getInstance() {
        return SingletonHolder.getInstance();
    }

    private static class SingletonHolder {
        private static ActiveModeDataUtil instance = new ActiveModeDataUtil();

        public static ActiveModeDataUtil getInstance() {
            return instance;
        }
    }

    public void setScanId(String scanId) {
        this.scanId = scanId;
    }

    public void setUserId(String userId) {

        this.userId = userId;
    }

    /*用于初始化一次采集，该方法在 Wifi采集结果的 onSuccess 中调用*/
    private void initScanTask() {

    }

    public void setWifiData(List<WifiDataResult> wifiDatas) {
        this.wifiDatas = wifiDatas;
        for (int i = 0, len = wifiDatas.size(); i < len; i++) {

            JSONStringer jsonStringer = new JSONStringer();
            WifiDataResult wifiDataResult = wifiDatas.get(i);

            try {
                jsonStringer.object();
                jsonStringer.key("singleintensity").value(wifiDataResult.getSingleIntensity());
                jsonStringer.key("timestamp").value(wifiDataResult.getTimestamp());
                jsonStringer.key("ssis").value(wifiDataResult.getSsid());
                jsonStringer.key("capability").value(wifiDataResult.getCapability());
                jsonStringer.key("bssid").value(wifiDataResult.getBssid());
                jsonStringer.key("scanid").value(wifiDataResult.getId());
                jsonStringer.key("frequency").value(wifiDataResult.getFrequency());
                jsonStringer.key("level").value(wifiDataResult.getLevel());
                jsonStringer.endObject();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            wifiJsonDatas.add(jsonStringer);
        }
    }

    public void setBluetoothData(BluetoothDataResult bluetoothData) {

        this.bluetoothData = bluetoothData;

        JSONStringer jsonStringer = new JSONStringer();
        try {
            jsonStringer.object();
            jsonStringer.key("timestamp").value(bluetoothData.getTimestamp());
            jsonStringer.key("address").value(bluetoothData.getAddress());
            jsonStringer.key("boundstate").value(bluetoothData.getBoundState());
            jsonStringer.key("scanid").value(bluetoothData.getId());
            jsonStringer.key("name").value(bluetoothData.getName());
            jsonStringer.key("rssi").value(bluetoothData.getRssi());
            jsonStringer.key("type").value(bluetoothData.getType());
            jsonStringer.endObject();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        bluetoothJsonDatas.add(jsonStringer);
    }

    public void setSensorData(SensorDataResult sensorData) {

        this.sensorData = sensorData;
//        JSONStringer jsonStringer = new JSONStringer();
//        try {
//            jsonStringer.object();
//            jsonStringer.key("sensorName").value(sensorData.getSensorName());
//            jsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
//            jsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
//            jsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));
////                    accJsonStringer.key("values").value(sensorData.getValues());
////                    accelerometerJsonStringer.key("values").value(sensorData.sensorValuesToString());
//            jsonStringer.key("values").array();
//            for (int i = 0, len = sensorData.getValues().length; i < len; i++) {
//                jsonStringer.value(sensorData.getValues()[i]);
//            }
//            jsonStringer.endArray();
//            jsonStringer.endObject();
//            sensorJsonDatas.add(jsonStringer);
//        } catch (JSONException e) {
//            e.printStackTrace();
//        }


//
//
        switch (sensorData.getSensorType()) {
            case Sensor.TYPE_ACCELEROMETER:
//                All values are in SI units (m/s^2)
//                values[0]: Acceleration minus Gx on the x-axis
//                values[1]: Acceleration minus Gy on the y-axis
//                values[2]: Acceleration minus Gz on the z-axis
                JSONStringer accelerometerJsonStringer = new JSONStringer();
                try {
                    accelerometerJsonStringer.object();
                    accelerometerJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    accelerometerJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    accelerometerJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    accelerometerJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));
//                    accJsonStringer.key("values").value(sensorData.getValues());
//                    accelerometerJsonStringer.key("values").value(sensorData.sensorValuesToString());
                    accelerometerJsonStringer.key("x-axis").value(sensorData.getValues()[0]);
                    accelerometerJsonStringer.key("y-axis").value(sensorData.getValues()[1]);
                    accelerometerJsonStringer.key("z-axis").value(sensorData.getValues()[2]);
                    accelerometerJsonStringer.endObject();
                    sensorJsonDatas.add(accelerometerJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_GYROSCOPE:
//                values[0]: Angular speed around the x-axis
//                values[1]: Angular speed around the y-axis
//                values[2]: Angular speed around the z-axis
                JSONStringer gyroscopeJsonStringer = new JSONStringer();
                try {
                    gyroscopeJsonStringer.object();
                    gyroscopeJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    gyroscopeJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    gyroscopeJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    gyroscopeJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

                    gyroscopeJsonStringer.key("x-axis").value(sensorData.getValues()[0]);
                    gyroscopeJsonStringer.key("y-axis").value(sensorData.getValues()[1]);
                    gyroscopeJsonStringer.key("z-axis").value(sensorData.getValues()[2]);

                    gyroscopeJsonStringer.endObject();
                    sensorJsonDatas.add(gyroscopeJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_GRAVITY:
//                values[0]: Force of gravity along the x axis.
//                values[1]: Force of gravity along the y axis.
//                values[2]: Force of gravity along the z axis.
                JSONStringer gravityJsonStringer = new JSONStringer();
                try {
                    gravityJsonStringer.object();
                    gravityJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    gravityJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    gravityJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    gravityJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

                    gravityJsonStringer.key("x-axis").value(sensorData.getValues()[0]);
                    gravityJsonStringer.key("y-axis").value(sensorData.getValues()[1]);
                    gravityJsonStringer.key("z-axis").value(sensorData.getValues()[2]);

                    gravityJsonStringer.endObject();
                    sensorJsonDatas.add(gravityJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_LINEAR_ACCELERATION:
//                values[0]: Acceleration force along the x axis (excluding gravity).
//                values[1]: Acceleration force along the y axis (excluding gravity).
//                values[2]: Acceleration force along the z axis (excluding gravity).
                JSONStringer linear_accelerationJsonStringer = new JSONStringer();
                try {
                    linear_accelerationJsonStringer.object();
                    linear_accelerationJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    linear_accelerationJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    linear_accelerationJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    linear_accelerationJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

                    linear_accelerationJsonStringer.key("x-axis").value(sensorData.getValues()[0]);
                    linear_accelerationJsonStringer.key("y-axis").value(sensorData.getValues()[1]);
                    linear_accelerationJsonStringer.key("z-axis").value(sensorData.getValues()[2]);
                    linear_accelerationJsonStringer.endObject();
                    sensorJsonDatas.add(linear_accelerationJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
//                The values array is shown below:
//                values[0] = x_bias
//                values[1] = y_bias
//                values[2] = z_bias
//                x_uncalib, y_uncalib, z_uncalib are the measured magnetic field in X, Y, Z axes.
//                Soft iron and temperature calibrations are applied. But the hard iron calibration is not applied.
//                 The values are in micro-Tesla (uT).
//
//                    x_bias, y_bias, z_bias give the iron bias estimated in X, Y, Z axes.
//                Each field is a component of the estimated hard iron calibration. The values are in micro-Tesla (uT).


                JSONStringer magneticJsonStringer = new JSONStringer();
                try {
                    magneticJsonStringer.object();
                    magneticJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    magneticJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    magneticJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    magneticJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

                    magneticJsonStringer.key("x_bias").value(sensorData.getValues()[0]);
                    magneticJsonStringer.key("y_bias").value(sensorData.getValues()[1]);
                    magneticJsonStringer.key("z_bias").value(sensorData.getValues()[2]);
                    magneticJsonStringer.endObject();
                    sensorJsonDatas.add(magneticJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_ORIENTATION:
//                values[0]: Azimuth, angle between the magnetic north direction and the y-axis, around the z-axis (0 to 359). 0=North, 90=East, 180=South, 270=West
//                values[1]: Pitch, rotation around x-axis (-180 to 180), with positive values when the z-axis moves toward the y-axis.
//                values[2]: Roll, rotation around the x-axis (-90 to 90) increasing as the device moves clockwise.
                JSONStringer orientationJsonStringer = new JSONStringer();
                try {
                    orientationJsonStringer.object();
                    orientationJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    orientationJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    orientationJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    orientationJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));
                    orientationJsonStringer.key("x-axis").value(sensorData.getValues()[0]);
                    orientationJsonStringer.key("y-axis").value(sensorData.getValues()[1]);
                    orientationJsonStringer.key("z-axis").value(sensorData.getValues()[2]);
                    orientationJsonStringer.endObject();
                    sensorJsonDatas.add(orientationJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_ROTATION_VECTOR:

//                values[0]: x*sin(θ/2)
//                values[1]: y*sin(θ/2)
//                values[2]: z*sin(θ/2)
//                values[3]: cos(θ/2)
//                values[4]: estimated heading Accuracy (in radians) (-1 if unavailable)
//                values[3], originally optional, will always be present from SDK Level 18 onwards. values[4] is a new value that has been added in SDK Level 18.


                JSONStringer rotation_vectorJsonStringer = new JSONStringer();
                try {
                    rotation_vectorJsonStringer.object();
                    rotation_vectorJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    rotation_vectorJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    rotation_vectorJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    rotation_vectorJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

                    rotation_vectorJsonStringer.key("x_bias").value(sensorData.getValues()[0]);
                    rotation_vectorJsonStringer.key("y_bias").value(sensorData.getValues()[1]);
                    rotation_vectorJsonStringer.key("z_bias").value(sensorData.getValues()[2]);
                    rotation_vectorJsonStringer.key("w_bias").value(sensorData.getValues()[3]);
                    rotation_vectorJsonStringer.key("e_bias").value(sensorData.getValues()[4]);

                    rotation_vectorJsonStringer.endObject();
                    sensorJsonDatas.add(rotation_vectorJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_STEP_DETECTOR:
                JSONStringer step_detectorJsonStringer = new JSONStringer();
                try {
                    step_detectorJsonStringer.object();
                    step_detectorJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    step_detectorJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    step_detectorJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    step_detectorJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

//                    String s = "";
//                    for (int i = 0, len = sensorData.getValues().length; i < len; i++) {
//                        s = sensorData.getValues()[i] + "#" + s;
//                    }

                    step_detectorJsonStringer.key("values").value(sensorData.getValues()[0]);
                    step_detectorJsonStringer.endObject();
                    sensorJsonDatas.add(step_detectorJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;
            case Sensor.TYPE_STEP_COUNTER:
                JSONStringer step_counterJsonStringer = new JSONStringer();
                try {
                    step_counterJsonStringer.object();
                    step_counterJsonStringer.key("sensorName").value(sensorData.getSensorName());
                    step_counterJsonStringer.key("sensorType").value(Integer.toString(sensorData.getSensorType()));
                    step_counterJsonStringer.key("timestamp").value(Long.toString(sensorData.getTimestamp()));
                    step_counterJsonStringer.key("accuracy").value(Integer.toString(sensorData.getAccuracy()));

                    step_counterJsonStringer.key("values").value(sensorData.getValues()[0]);

                    step_counterJsonStringer.endObject();
                    sensorJsonDatas.add(step_counterJsonStringer);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                break;


        }
    }

    public void setSensorAccuracyChanged(Sensor sensor, int accuracy) {

    }

    public void handlerData() {
//        initScanTask();
        new HandlerDataThread().execute();
    }

    private class HandlerDataThread extends SimpleSafeTask {

        @Override
        protected Object doInBackgroundSafely() throws Exception {


            JSONStringer jsonStringer = new JSONStringer();

            jsonStringer.object();

            //put bluetooth data to json
            jsonStringer.key("bluetooth").array();
            for (int i = 0, len = bluetoothJsonDatas.size(); i < len; i++) {
                jsonStringer.value(bluetoothJsonDatas.get(i));
            }
            jsonStringer.endArray();

            bluetoothJsonDatas.clear();

            //put wifi data to json
            jsonStringer.key("wifi").array();
            for (int i = 0, len = wifiJsonDatas.size(); i < len; i++) {
                jsonStringer.value(wifiJsonDatas.get(i));
            }
            jsonStringer.endArray();
            wifiJsonDatas.clear();

            //put sensor data to json
            jsonStringer.key("sensor").array();

            for (int i = 0, len = sensorJsonDatas.size(); i < len; i++) {
                jsonStringer.value(sensorJsonDatas.get(i));
            }

            jsonStringer.endArray();
            sensorJsonDatas.clear();


            jsonStringer.endObject();
//            Log.d(ActiveModeDataUtil.class.getSimpleName(), "####JSON####" + jsonStringer.toString());
            return null;
        }
    }
}


